home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 4_2005-2006.ISO / data / Zips / ParaPing_1189890692005.psc / Just the Control / ucParaPing.ctl < prev    next >
Text File  |  2005-06-09  |  28KB  |  814 lines

  1. VERSION 5.00
  2. Object = "{248DD890-BB45-11CF-9ABC-0080C7E7B78D}#1.0#0"; "MSWINSCK.OCX"
  3. Begin VB.UserControl ucParaPing 
  4.    CanGetFocus     =   0   'False
  5.    ClientHeight    =   1560
  6.    ClientLeft      =   0
  7.    ClientTop       =   0
  8.    ClientWidth     =   3930
  9.    HasDC           =   0   'False
  10.    InvisibleAtRuntime=   -1  'True
  11.    Picture         =   "ucParaPing.ctx":0000
  12.    ScaleHeight     =   1560
  13.    ScaleWidth      =   3930
  14.    ToolboxBitmap   =   "ucParaPing.ctx":0974
  15.    Begin MSWinsockLib.Winsock wsckArrPing 
  16.       Index           =   1
  17.       Left            =   1500
  18.       Top             =   645
  19.       _ExtentX        =   741
  20.       _ExtentY        =   741
  21.       _Version        =   393216
  22.       Protocol        =   1
  23.       RemotePort      =   7
  24.    End
  25.    Begin VB.Timer tmrSchedule 
  26.       Enabled         =   0   'False
  27.       Interval        =   20
  28.       Left            =   915
  29.       Top             =   630
  30.    End
  31. End
  32. Attribute VB_Name = "ucParaPing"
  33. Attribute VB_GlobalNameSpace = False
  34. Attribute VB_Creatable = True
  35. Attribute VB_PredeclaredId = False
  36. Attribute VB_Exposed = False
  37.  
  38. '
  39. '   ParaPING 1.0
  40. '
  41.  
  42. '   Multiple parallel PINGs to many destination hosts.
  43. '
  44. '   If you wants to know within a few seconds which of
  45. '   the 5000 machines in your local area network are really
  46. '   running this ones for you! ;-)
  47.  
  48. '   Project started in April 2005 by Light Templer
  49.  
  50. '   Last edit:  6/9/2005
  51.  
  52.  
  53. Option Explicit
  54.  
  55.  
  56. '   Description:
  57. '
  58. '   Using the AddHost() function IP adresses are added to a ring buffer.
  59. '   From there the timer loop (worker loop) fetches them one bye one,
  60. '   put them into a list with infomations about running Pings and sends
  61. '   a Ping (in fact it opens a connection to port 7) to the destination host.
  62. '   The Pings are realized by a control array of WinSock controls, not by
  63. '   any API (ICMP) calls. This way we have a kind of a "multi threading" in
  64. '   pure VB without any dirty tricks, memory errors or any other problems.
  65. '
  66. '   That means: You can run 50 or more Pings asyncron the same time and
  67. '   your GUI (form) stays fully responsible and interactive ...  ;-)
  68. '   So checking hundreds or thousands of machines can be done in just a few
  69. '   secondes.
  70.  
  71.  
  72.  
  73. ' ******************************
  74. ' *           EVENTS           *
  75. ' ******************************
  76. Public Event Pong(sIPadr As String, lID As Long, flgSuccess As Boolean)     ' Gives result of a Ping: 'Dead' or 'alive'
  77. Public Event StateChanged(New_State As enState, sNewState As String)        ' Informs about any changes in ParaPings state
  78. Public Event Error(Errorcode As enErrorCodes, sErr As String)               ' An error has occourd
  79.  
  80.  
  81.  
  82.  
  83. ' ******************************
  84. ' *      PUBLIC ENUMS          *
  85. ' ******************************
  86. Public Enum enState
  87.     PP_IDLE = 0
  88.     PP_BUSY = 1
  89.     PP_DISABLED = 2
  90.     PP_ABORT_PENDING = 3
  91. End Enum
  92.  
  93. Public Enum enErrorCodes
  94.     PP_ERR_NO_ERROR = 0
  95.     PP_ERR_GENERAL_ERROR = 1
  96.     PP_ERR_BUFFER_OVERFLOW = 2
  97.     PP_ERR_WRONG_PARAMETER = 3
  98.     PP_ERR_NOT_IDLE = 4
  99.     PP_ERR_WINSOCK = 5
  100. End Enum
  101.  
  102.  
  103.  
  104. ' ******************************
  105. ' *           CONSTS           *
  106. ' ******************************
  107. Const THREADLIMIT           As Long = 100&              ' Upper limit for number of simultan Pings
  108. Const QUEUELIMIT            As Long = 20000&            ' Max IP adresses in queue waiting for a Ping
  109. Const MAXTIMEOUT            As Long = 10&               ' Max number of seconds to wait for an answer to a Ping
  110. Const PING_PORT             As Long = 7&                ' TCP port for Ping (ICMP)
  111.  
  112.  
  113.  
  114. ' ******************************
  115. ' *       DEFAULT VALUES       *
  116. ' ******************************
  117. Const DEFAULT_MAXTHREADS    As Long = 10&               ' Default value for upper limit for number of simultan Pings
  118. Const DEFAULT_QUEUESIZE     As Long = 500&              ' Default value for max IP adresses in queue waiting for a Ping
  119. Const DEFAULT_TIMEOUT       As Long = 3&                ' Default value for timeout for Ping
  120.  
  121.  
  122.  
  123.  
  124. ' ******************************
  125. ' *         LOCAL UDTs         *
  126. ' ******************************
  127.  
  128. Private Type tpDestHost
  129.     sIPadr                  As String                   ' IP adress of destination host in usual form, e.g.  "130.112.50.10"
  130.     lID                     As Long                     ' Any Id (number) the uc user wants, e.g. an index into an array or listview
  131. End Type
  132.  
  133. Private Type tpThread
  134.     sIPadr                  As String                   ' IP adress of destination host in usual form, e.g.  "130.112.50.10"
  135.     lID                     As Long                     ' Any Id (number) the uc user wants, e.g. an index into an array or listview
  136.     lStartTime              As Long                     ' Got with VBs timer function:  Int(Timer())
  137.     flgPong                 As Boolean                  ' Set to TRUE, when we get an answer from destination host
  138. End Type
  139.  
  140. Private Type tpVAR
  141.     flgEnabled              As Boolean                  ' TRUE: Adding a new host with 'AddHost' immediatly starts checking
  142.     State                   As enState                  ' Current state of ParaPING control
  143.     lOpenPings              As Long                     ' Running 'Pings' waiting for their 'Pongs'
  144.     lMaxThreads             As Long                     ' How many Pings at the same time
  145.     lTimeout                As Long                     ' Timeout for Ping result in seconds (min. 1)
  146.     lWaitingInQueue         As Long                     ' How many host entries in queue are waiting for their check by Ping
  147.     lQueueSize              As Long                     ' Size of queue with host entries
  148.     lNxtFreePosInQueue      As Long                     ' Pointer into ringbuffer:  Next free position to save an entry.
  149.     lNxtItemToTakeFromQueue As Long                     ' Pointer into ringbuffer:  Position of next entry to handle.
  150.     sLastErr                As String                   ' The last resulted error message raised by 'RaiseError'. Empty when no error.
  151.     LastErrorCode           As enErrorCodes             ' The last resulted error code.
  152. End Type
  153.  
  154.  
  155.  
  156. ' ******************************
  157. ' *         LOCAL VARs         *
  158. ' ******************************
  159.  
  160. Private VAR                 As tpVAR                    ' Holds all vars of the control (no the arrays!)
  161. Private arrQueueDestHosts() As tpDestHost               ' Host entries waiting for their check by Ping. Organiced as a ringbuffer
  162. Private arrThreads()        As tpThread                 ' Running 'Pings'. Organiced with empty and used slots.
  163. '
  164. '
  165. '
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172. ' ******************************
  173. ' *        ALL USERCONTROL     *
  174. ' ******************************
  175. Private Sub UserControl_Initialize()
  176.     
  177.     ' Nothing yet
  178.     
  179. End Sub
  180.  
  181.  
  182. Private Sub UserControl_Terminate()
  183.     
  184.     Call Me.Abort
  185.     If VAR.State = PP_IDLE Then
  186.         Call FreeResources
  187.     End If
  188.     
  189. End Sub
  190.  
  191.  
  192. Private Sub UserControl_InitProperties()
  193.     
  194.     With VAR
  195.         .lQueueSize = DEFAULT_QUEUESIZE
  196.         .lMaxThreads = DEFAULT_MAXTHREADS
  197.         .lTimeout = DEFAULT_TIMEOUT
  198.     End With
  199.     
  200.     With wsckArrPing(1)
  201.         .Protocol = sckUDPProtocol                          ' We need the connectionless UDP protocol
  202.         .RemotePort = PING_PORT
  203.     End With
  204.     
  205. End Sub
  206.  
  207. Private Sub UserControl_Resize()
  208.     
  209.     Const ucWIDTH = 420
  210.     
  211.     UserControl.Width = ucWIDTH
  212.     UserControl.Height = ucWIDTH
  213.     
  214. End Sub
  215.  
  216.  
  217. Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  218.     
  219.     With VAR
  220.         .lMaxThreads = PropBag.ReadProperty("MaxThreads", DEFAULT_MAXTHREADS)
  221.         .lQueueSize = PropBag.ReadProperty("QueueSize", DEFAULT_QUEUESIZE)
  222.         .lTimeout = PropBag.ReadProperty("Timeout", DEFAULT_TIMEOUT)
  223.         
  224.         ' Init on app start
  225.         If Ambient.UserMode = True Then
  226.         
  227.             ' Setup arrays
  228.             ReDim arrQueueDestHosts(1 To .lQueueSize)
  229.             ReDim arrThreads(1 To .lMaxThreads)
  230.             
  231.             ' Set pointers into ringbuffer to start position
  232.             .lNxtFreePosInQueue = 1
  233.             .lNxtItemToTakeFromQueue = 1
  234.             
  235.             ' All to 'idle'
  236.             SetStateTo PP_IDLE
  237.             ClearError
  238.             
  239.         End If
  240.     End With
  241.     
  242. End Sub
  243.  
  244.  
  245. Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  246.  
  247.     With PropBag
  248.         Call .WriteProperty("MaxThreads", VAR.lMaxThreads, DEFAULT_MAXTHREADS)
  249.         Call .WriteProperty("QueueSize", VAR.lQueueSize, DEFAULT_QUEUESIZE)
  250.         Call .WriteProperty("Timeout", VAR.lTimeout, DEFAULT_TIMEOUT)
  251.     End With
  252.     
  253. End Sub
  254.  
  255.  
  256.  
  257.  
  258.  
  259. ' ******************************
  260. ' *       PUBLIC METHODS       *
  261. ' ******************************
  262.  
  263. Public Function About()
  264. Attribute About.VB_Description = "Gives some information to the ParaPing control in a message box."
  265. Attribute About.VB_UserMemId = -552
  266.     ' Show a little 'About this control' message box
  267.  
  268.     MsgBox "ParaPing V." & App.Major & "." & App.Minor & App.Revision & _
  269.             " - June 2005 by Light Templer", vbInformation + vbOKOnly, " About  'ParaPing'"
  270.  
  271. End Function
  272.  
  273.  
  274. Public Function AddHost(sIPadress As String, Optional lID As Long = 0) As Boolean
  275. Attribute AddHost.VB_UserMemId = 0
  276.     ' Adds an IP adress of a destination host and an (optinal, user random defined)
  277.     ' ID number to the ring buffer. From there its taken to create a 'thread' to
  278.     ' check up or down by PING.
  279.     ' If current state isn't 'Disabled' adding a new host starts checking!
  280.     '
  281.     ' RESULT:  TRUE,  if adding to queue was successful.
  282.     '          FALSE, if no more empty space in queue to hold the adress or
  283.     '                 IP adress has invalid format.
  284.     
  285.     On Local Error GoTo AddHost_Error
  286.     
  287.     ClearError
  288.     
  289.     With VAR
  290.         ' Is there a free slot to hold another IP adress?
  291.         If .lWaitingInQueue >= .lQueueSize Then
  292.             RaiseError PP_ERR_BUFFER_OVERFLOW, "Buffer limit (" & .lQueueSize & ") reached. Cannot add more IP adresses!"
  293.         
  294.             Exit Function
  295.         End If
  296.         
  297.         ' IP adress must be valid
  298.         If IsValidIP(sIPadress) = False Then
  299.             RaiseError PP_ERR_WRONG_PARAMETER, "Not a valid IP adress. ID= " & lID & " / IP= '" & sIPadress & "'"
  300.             
  301.             Exit Function
  302.         End If
  303.         
  304.         ' Put the new entry into the ringbuffer
  305.         With arrQueueDestHosts(.lNxtFreePosInQueue)
  306.             .sIPadr = sIPadress
  307.             .lID = lID
  308.         End With
  309.         .lWaitingInQueue = .lWaitingInQueue + 1
  310.         
  311.         ' Increment buffer pointer. If upper border reached restart from slot no 1
  312.         .lNxtFreePosInQueue = .lNxtFreePosInQueue + 1
  313.         If .lNxtFreePosInQueue > .lQueueSize Then
  314.             .lNxtFreePosInQueue = 1
  315.         End If
  316.         
  317.         ' Enable pinging to hosts if control is in enabled state
  318.         If .flgEnabled = True And tmrSchedule.Enabled = False Then
  319.             tmrSchedule.Enabled = True
  320.         End If
  321.         
  322.     End With
  323.     
  324.     ' Success!
  325.     AddHost = True
  326.  
  327.    
  328.     Exit Function
  329.  
  330. AddHost_Error:
  331.  
  332.     RaiseError PP_ERR_GENERAL_ERROR, "[" & Err.Number & "] - '" & Err.Description & "' in AddHost() of 'ucParaPing'"
  333.     
  334. End Function
  335.  
  336.  
  337. Public Sub Enable()
  338.     ' Start checking hosts in queue until queue is empty and stay on 'enabled' state
  339.     ' when all checks are done. In 'enabled' state adding a new host with 'AddHost'
  340.     ' immediatly starts checking again!
  341.  
  342.     VAR.flgEnabled = True
  343.     If tmrSchedule.Enabled = False Then
  344.         tmrSchedule.Enabled = True
  345.     End If
  346.     ClearError
  347.     
  348. End Sub
  349.  
  350.  
  351. Public Sub ClearQueue()
  352.     ' Host entries in queue will be cleared. (In fact just a reset for the pointers,
  353.     ' no need to run through the whole array and clear every item.
  354.     ' Running checks (current 'threads') WILL BE raised with success/fail
  355.     ' until all open Pings are done.
  356.     
  357.     With VAR
  358.         .lWaitingInQueue = 0
  359.         .lNxtFreePosInQueue = 1
  360.         .lNxtItemToTakeFromQueue = 1
  361.     End With
  362.     ClearError
  363.  
  364. End Sub
  365.  
  366.  
  367. Public Sub Disable()
  368.     ' Don't check hosts from queue anymore.
  369.     ' Host entries remains in queue waiting for a call to 'Enable' .
  370.     ' Running checks (current threads) ARE raised with success/fail until
  371.     ' all open threads are done.
  372.  
  373.     SetStateTo PP_DISABLED
  374.     VAR.flgEnabled = False
  375.     If VAR.lOpenPings = 0 Then
  376.         ' No more checking the lists
  377.         tmrSchedule.Enabled = False
  378.     End If
  379.     
  380. End Sub
  381.  
  382.  
  383. Public Sub Abort()
  384.     ' Don't check hosts from queue anymore.
  385.     ' Host entries remains in queue.
  386.     ' Running checks (current threads) WILL NOT BE raised anymore.
  387.     ' Thread list will be cleared.
  388.     ' 'State' is going to be 'disabled'
  389.     
  390.     VAR.lOpenPings = 0
  391.     SetStateTo IIf(VAR.lOpenPings > 0, PP_ABORT_PENDING, PP_DISABLED)
  392.     VAR.flgEnabled = False
  393.  
  394. End Sub
  395.  
  396.  
  397. Public Sub FreeResources()
  398.     ' Unload no more needed elements from WinSock control array
  399.     ' If you worked with lot of 'threads' (more than 20?) this could be a good
  400.     ' idea to save resources.
  401.     
  402.     Dim i As Long
  403.  
  404.     If VAR.State <> PP_IDLE And wsckArrPing.Count > 1 Then
  405.         RaiseError PP_ERR_NOT_IDLE, "IDLE state needed to unload no more needed elements from WinSock control array!"
  406.     
  407.         Exit Sub
  408.     End If
  409.     
  410.     ' Top down unloading the control array elements up to the first which remains always.
  411.     For i = wsckArrPing.Count To 2 Step -1
  412.         Unload wsckArrPing(i)
  413.     Next i
  414.     
  415. End Sub
  416.  
  417.  
  418.  
  419.  
  420. ' ******************************
  421. ' *   PRIVATE SUBS/FUNCTIONS   *
  422. ' ******************************
  423. Private Sub RaiseError(Errorcode As enErrorCodes, sErr As String)
  424.     ' Centralized for easy changes/additions
  425.     
  426.     VAR.sLastErr = sErr
  427.     VAR.LastErrorCode = Errorcode
  428.     
  429.     RaiseEvent Error(Errorcode, sErr)
  430.  
  431. End Sub
  432.  
  433.  
  434. Private Sub ClearError()
  435.  
  436.     VAR.sLastErr = ""
  437.     VAR.LastErrorCode = PP_ERR_NO_ERROR
  438.     
  439. End Sub
  440.  
  441. Private Sub SetStateTo(NewState As enState)
  442.     ' Centralized for easy changes/additions
  443.         
  444.     Dim sState As String
  445.     
  446.     VAR.State = NewState
  447.     
  448.     sState = Choose(NewState + 1, "Idle", "Busy", "Disabled", "AbortPending")
  449.     RaiseEvent StateChanged(NewState, sState)
  450.     
  451. End Sub
  452.  
  453. Private Sub wsckArrPing_DataArrival(Index As Integer, ByVal bytesTotal As Long)
  454.     ' PONG! We just get an answer from the destination host so we save this result quickly!
  455.     ' Rasing this result to the user is a job of the timer loop "tmrSchedule_Timer()".
  456.     
  457.     arrThreads(Index).flgPong = True
  458.     
  459. End Sub
  460.  
  461. Private Sub wsckArrPing_Error(Index As Integer, ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
  462.     ' Give the error to the user
  463.     
  464.     RaiseError PP_ERR_WINSOCK, "WinSock control pinging to '" & arrThreads(Index).sIPadr & "' gots error [" & Description & "]"
  465.  
  466. End Sub
  467.  
  468.  
  469. Private Sub tmrSchedule_Timer()
  470.     ' Main action starts here:
  471.     '
  472.     ' When enabled and there are hosts to check in queue create 'threads'
  473.     ' to check the destination hosts by using a WinSock control array.
  474.     ' 'Ping' is realized by opening a connection to ICMP (Ping) port 7.
  475.  
  476.  
  477.     Dim i               As Long
  478.     Dim lStartSearch    As Long
  479.     Dim lIndexFree      As Long
  480.     Dim EmptySlot       As tpThread
  481.     
  482.     
  483.     On Local Error GoTo tmrSchedule_Timer_Error
  484.  
  485.  
  486.     With VAR
  487.     
  488.         ' === PART 1 :     Handle running 'threads' first to get free slots for new 'threads'
  489.         If .lOpenPings > 0 Then
  490.             For i = 1 To wsckArrPing.Count                                          ' Check allocated slots (1..n)
  491.                 With arrThreads(i)
  492.                     If .flgPong = True Then                                         ' Did we got an answer to the Ping call?
  493.                         RaiseEvent Pong(.sIPadr, .lID, True)                        ' Let the world know we got an answer!
  494.                         Let arrThreads(i) = EmptySlot                               ' Free thread
  495.                         VAR.lOpenPings = VAR.lOpenPings - 1                         ' One less
  496.                         
  497.                     ElseIf Len(.sIPadr) Then                                        ' Used slot?
  498.                         If .lStartTime + VAR.lTimeout < Int(Timer()) Then           ' Is 'thread' timed out?
  499.                             RaiseEvent Pong(.sIPadr, .lID, False)                   ' Let the world know we didn't got an answer!
  500.                             Let arrThreads(i) = EmptySlot                           ' Free thread
  501.                             VAR.lOpenPings = VAR.lOpenPings - 1                     ' One less
  502.                             
  503.                         End If
  504.                     
  505.                     ' Else   Do nothing and go on waiting
  506.                     
  507.                     End If
  508.                 End With
  509.                 
  510.                 ' Abort check if no more runnings or user called Abort()
  511.                 If .lOpenPings = 0 Then
  512.                     
  513.                     Exit For
  514.                 End If
  515.                 
  516.             Next i
  517.             
  518.             ' User has disabled and we are not waiting for results of running Pings anymore
  519.             If .lOpenPings = 0 And VAR.State = PP_DISABLED Then
  520.                 ' No more checking the lists
  521.                 tmrSchedule.Enabled = False
  522.                 
  523.                 Exit Sub
  524.             End If
  525.                 
  526.         ElseIf .lWaitingInQueue = 0 Then            ' All is done -> stop timer!
  527.             ' No more checking the lists
  528.             tmrSchedule.Enabled = False
  529.                 
  530.             Exit Sub
  531.             
  532.         End If
  533.         
  534.         ' Abort request by user ?
  535.         If VAR.State = PP_ABORT_PENDING Then
  536.             
  537.             ' Clear 'thread' list
  538.             For i = 1 To wsckArrPing.Count
  539.                 Let arrThreads(i) = EmptySlot
  540.             Next i
  541.             
  542.             ' Don' check lists anymore
  543.             tmrSchedule.Enabled = False
  544.             
  545.             ' Set new state
  546.             SetStateTo PP_DISABLED
  547.             
  548.             Exit Sub
  549.         End If
  550.         
  551.         DoEvents
  552.         
  553.         
  554.         
  555.         ' === PART 2 :     Create new 'threads' if entries are waiting in queue
  556.         lStartSearch = 1                                                            ' Start index for search in "thread"-list
  557.         Do While .lWaitingInQueue > 0 And _
  558.                 .lOpenPings < .lMaxThreads And _
  559.                 VAR.flgEnabled = True                                               ' Entries are waiting, we have free slots and
  560.                                                                                     ' control is enabled
  561.             SetStateTo PP_BUSY
  562.             
  563.             ' Search for a free slot within current lists dimension
  564.             lIndexFree = 0                                                          ' 0 = Not found a free slot
  565.             For i = lStartSearch To wsckArrPing.Count
  566.                 If Len(arrThreads(i).sIPadr) = 0 Then
  567.                     lIndexFree = i                                                  ' Found a free slot
  568.                     lStartSearch = lIndexFree + 1
  569.                     
  570.                     Exit For
  571.                 End If
  572.             Next i
  573.             
  574.             ' If we still need a free slot
  575.             If lIndexFree = 0 And wsckArrPing.Count < .lMaxThreads Then             ' Not found a free slot, but space for a new one
  576.                 lIndexFree = wsckArrPing.Count + 1
  577.                 Load wsckArrPing(lIndexFree)                                        ' Load a new WinSock control in control array
  578.                 lStartSearch = lIndexFree + 1                                       ' In this way we don't search for a free slot
  579.             End If                                                                  ' on the next cycle of this big loop.
  580.             
  581.             
  582.             ' If we still don't have a free slot so we must abort for this time
  583.             If lIndexFree = 0 Then
  584.             
  585.                 Exit Do
  586.             End If
  587.  
  588.             ' Now all its done for the Ping
  589.             With arrThreads(lIndexFree)
  590.                 .sIPadr = arrQueueDestHosts(VAR.lNxtItemToTakeFromQueue).sIPadr     ' Take next item from ringbuffer and
  591.                 .lID = arrQueueDestHosts(VAR.lNxtItemToTakeFromQueue).lID           ' put it into 'thread' list
  592.                 .lStartTime = Int(Timer())
  593.                 .flgPong = False
  594.                             
  595.                 wsckArrPing(lIndexFree).RemoteHost = .sIPadr                        ' HERE we "PING" to the dest host just by opening
  596.                 wsckArrPing(lIndexFree).SendData "<PONG this!>"                     ' a connection to port 7 and sending a string.
  597.             End With
  598.             
  599.             ' Handle ringbuffer
  600.             .lOpenPings = .lOpenPings + 1                                           ' One more open Pings we wait for
  601.             .lWaitingInQueue = .lWaitingInQueue - 1                                 ' One less in queue to do
  602.             If .lWaitingInQueue > 0 Then
  603.                 .lNxtItemToTakeFromQueue = .lNxtItemToTakeFromQueue + 1
  604.                 If .lNxtItemToTakeFromQueue > .lQueueSize Then
  605.                     .lNxtItemToTakeFromQueue = 1
  606.                 End If
  607.                 
  608.             Else
  609.                 ' Reset pointers to start when buffer empty
  610.                 .lNxtFreePosInQueue = 1
  611.                 .lNxtItemToTakeFromQueue = 1
  612.                 
  613.             End If
  614.         Loop
  615.         
  616.         ' Ready
  617.         If .lOpenPings = 0 Then
  618.             SetStateTo PP_IDLE
  619.         End If
  620.         
  621.     End With
  622.    
  623.     Exit Sub
  624.  
  625. tmrSchedule_Timer_Error:
  626.  
  627.     RaiseEvent Error(PP_ERR_GENERAL_ERROR, "Error " & Err.Number & " [" & Err.Description & "] in sub tmrSchedule_Timer() / 'ucParaPing'")
  628.  
  629. End Sub
  630.  
  631.  
  632. Private Function IsValidIP(sIPadress As String) As Boolean
  633.     ' My solution to the "IsValidIP()" theme ;-)
  634.     ' Optimized for speed and readability.
  635.     ' Ignores the 'logical' checks which are related to subnet mask.
  636.     '
  637.     ' 6/6/2005 - Light Templer
  638.     
  639.     Dim i       As Long
  640.     Dim lLen    As Long
  641.     Dim lDigit  As Long
  642.     Dim varArr  As Variant
  643.     
  644.     
  645.     
  646.     ' Min/max length
  647.     lLen = Len(sIPadress)
  648.     If lLen < 7 Or lLen > 15 Then Exit Function
  649.     
  650.     ' Valid chars only.
  651.     For i = 1 To lLen
  652.         If InStr(".0123456789", Mid$(sIPadress, i, 1)) = 0 Then Exit Function
  653.     Next i
  654.     
  655.     ' 3 dots
  656.     varArr = Split(sIPadress, ".")
  657.     If UBound(varArr) <> 3 Then Exit Function
  658.     
  659.     ' Check all 4 entries
  660.     For i = 0 To 3
  661.     
  662.         ' No empty entry
  663.         If Len(varArr(i)) = 0 Then Exit Function
  664.     
  665.         ' Max valid value
  666.         lDigit = Val(varArr(i))
  667.         If lDigit > 255 Then Exit Function
  668.         
  669.         ' Special check for first entry: 0 and 255 not allowed
  670.         If i = 0 And (lDigit = 0 Or lDigit = 255) Then Exit Function
  671.                 
  672.     Next i
  673.     
  674.     IsValidIP = True
  675.  
  676. End Function
  677.  
  678.  
  679.  
  680. ' ******************************
  681. ' *         PROPERTIES         *
  682. ' ******************************
  683.  
  684. Public Property Get PingsEnabled() As Boolean
  685.     
  686.     PingsEnabled = VAR.flgEnabled
  687.     
  688. End Property
  689.  
  690.  
  691. Public Property Get State() As enState
  692. Attribute State.VB_Description = "Idle or running Pings?"
  693. Attribute State.VB_MemberFlags = "400"
  694.     
  695.     State = VAR.State
  696.     
  697. End Property
  698.  
  699.  
  700. Public Property Get OpenPings() As Long
  701. Attribute OpenPings.VB_Description = "How many open Pings are running?"
  702.     
  703.     OpenPings = VAR.lOpenPings
  704.  
  705. End Property
  706.  
  707. Public Property Get LastErrorMsg() As String
  708.     
  709.     LastErrorMsg = VAR.sLastErr
  710.  
  711. End Property
  712.  
  713. Public Property Get MaxThreads() As Long
  714. Attribute MaxThreads.VB_Description = "How many parallel threads allowed?"
  715.     
  716.     MaxThreads = VAR.lMaxThreads
  717.  
  718. End Property
  719.  
  720.  
  721. Public Property Let MaxThreads(ByVal lNew_MaxThreads As Long)
  722.     ' Every additional 'thread' loads when used another Winsock control,
  723.     ' so be careful with this resource ... ;-)
  724.     
  725.     If VAR.State <> PP_IDLE Then
  726.         RaiseError PP_ERR_NOT_IDLE, "IDLE state needed to change max number of threads!"
  727.     
  728.         Exit Property
  729.     End If
  730.     
  731.     If lNew_MaxThreads > 0 And lNew_MaxThreads <= THREADLIMIT Then
  732.         VAR.lMaxThreads = lNew_MaxThreads
  733.         ReDim arrThreads(1 To lNew_MaxThreads)
  734.         PropertyChanged "MaxThreads"
  735.         ClearError
  736.     Else
  737.         RaiseError PP_ERR_WRONG_PARAMETER, "Invalid parameter for 'MaxThreads' (" & lNew_MaxThreads & ") Valid is 1 to " & THREADLIMIT & "."
  738.     End If
  739.     
  740. End Property
  741.  
  742.  
  743. Public Property Get QueueSize() As Long
  744. Attribute QueueSize.VB_Description = "Max number of stacked requests allowed to wait for a PING"
  745.     
  746.     QueueSize = VAR.lQueueSize
  747.  
  748. End Property
  749.  
  750. Public Property Let QueueSize(ByVal lNew_QueueSize As Long)
  751.     ' The queue is an array build of 'tpDestHost', one long and one
  752.     ' string per entry. Even for larger LANs with 5000 machines this shouldn't
  753.     ' be a problem of available memory. Anyway, to recycle no more used slots
  754.     ' this queue is organized as a ringbuffer and starts adding from beginning
  755.     ' using resolved (free) slots when the end is reached.
  756.     
  757.     If VAR.State <> PP_IDLE Then
  758.         RaiseError PP_ERR_NOT_IDLE, "IDLE state needed to change queue size!"
  759.     
  760.         Exit Property
  761.     End If
  762.     
  763.     If lNew_QueueSize > 0 And lNew_QueueSize <= QUEUELIMIT Then
  764.         VAR.lQueueSize = lNew_QueueSize
  765.         ReDim arrQueueDestHosts(1 To lNew_QueueSize)
  766.         PropertyChanged "QueueSize"
  767.         ClearError
  768.     Else
  769.         RaiseError PP_ERR_WRONG_PARAMETER, "Invalid parameter for 'QueueSize' (" & lNew_QueueSize & ") Valid is 1 to " & _
  770.                 QUEUELIMIT & "."
  771.     End If
  772.     
  773. End Property
  774.  
  775.  
  776. Public Property Get WaitingInQueue() As Long
  777. Attribute WaitingInQueue.VB_MemberFlags = "400"
  778.     
  779.     WaitingInQueue = VAR.lWaitingInQueue
  780.  
  781. End Property
  782.  
  783.  
  784. Public Property Get Timeout() As Long
  785. Attribute Timeout.VB_Description = "How many seconds to wait for an answer to a Ping call."
  786.     
  787.     Timeout = VAR.lTimeout
  788.  
  789. End Property
  790.  
  791. Public Property Let Timeout(ByVal lNew_Timeout As Long)
  792.     ' If timeout is reached for a destination host the request will
  793.     ' resolved as 'not reached'.
  794.     
  795.     If lNew_Timeout > 0 And lNew_Timeout <= MAXTIMEOUT Then
  796.         VAR.lTimeout = lNew_Timeout
  797.         PropertyChanged "QueueSize"
  798.     Else
  799.         RaiseError PP_ERR_WRONG_PARAMETER, "Invalid value for new timeout (" & lNew_Timeout & ")!  Must be from 1 to " & MAXTIMEOUT
  800.     End If
  801.         
  802. End Property
  803.  
  804.  
  805. Public Property Get WinSockArrSize() As Long
  806.     ' How many elements of the WinSock control array are currently loaded
  807.     
  808.     WinSockArrSize = wsckArrPing.Count
  809.  
  810. End Property
  811.  
  812.  
  813. ' #*#
  814.